package models

import (
	"cdam/lib"
	"errors"
	"fmt"
	"reflect"
	"strings"

	"github.com/astaxie/beego/orm"
)

type USER struct {
	Id       int    `orm:"column(id);pk"`
	Username string `orm:"column(username);null"`
	Password string `orm:"column(password);null"`
	Name     string `orm:"column(name);null"`
	Email    string `orm:"column(email);null"`
	Phone    string `orm:"column(phone);null"`
	Islock   string `orm:"column(islock);null"`
	Isdelete string `orm:"column(isdelete);null"`
	Orgid	 lib.NullInt64 `orm:"column(orgid);null"`
	Positionid lib.NullInt64 `orm:"column(positionid);null"`
	Staffnum string `orm:"column(staffnum);null"`
	Tenant  lib.NullInt64 `orm:"column(tenant);null"`
	Createdate lib.Time `orm:"column(createdate);null"`
	Updatedate lib.Time `orm:"column(updatedate);null"`
	Creater lib.NullInt64 `orm:"column(creater);null"`
	Updater lib.NullInt64 `orm:"column(updater);null"`
	Salt string `orm:"column(salt);null"`
}

type UserPath struct {
	Orgpath string
	Positionpath string
}

func (t *USER) TableName() string {
	return "t_sys_user"
}

func init() {
	orm.RegisterModel(new(USER))
}

func GetUserByRole(roleid int64) ([]USER,error) {
	o:= orm.NewOrm()
	var users []USER
	sql := "SELECT s.* FROM  t_sys_user_role r  left join t_sys_user s on  r.user_id = s.id where r.role_id = ?"
	_,err := o.Raw(sql,roleid).QueryRows(&users)
	if err == nil {
		return users,nil
	}else {
		return nil,err
	}
}

// 获取上级
func GetUserPath(id int64,level int) ([]USER,error) {
	var result []USER
	sql := "SELECT " +
				"o.PATH orgpath, " +
				"P.PATH AS positionpath " +
			"FROM " +
				"PUBLIC.T_SYS_USER R " +
			"LEFT JOIN " +
				"PUBLIC.T_SYS_ORG O " +
			"ON " +
				"R.orgid = O.ID " +
			"LEFT JOIN " +
				"PUBLIC.t_sys_position P " +
			"ON " +
				"R.positionid = P.ID " +
			"WHERE " +
				"r.id = ? "
	o := orm.NewOrm()
	var userpath UserPath
	if err := o.Raw(sql,id).QueryRow(&userpath); err == nil {
		positions := strings.Split(userpath.Positionpath,"_")
		levels := len(positions)
		var pid string
		if levels > level {
			pid = positions[levels - level]
		}else{
			return nil,errors.New("无法找到该员工的上级")
		}
		_, err = o.QueryTable("t_sys_user").Filter("positionid",pid).All(&result)
		return result, err
		// position := userpath.Positionpathlen(strings.Split(userpath.Positionpath, "_")) - 1
	}else{
		return nil, err
	}


}

// AddTSYSUSER insert a new TSYSUSER into database and returns
// last inserted Id on success.
func AddUSER(m *USER) (id int64, err error) {
	o := orm.NewOrm()
	count, _ := o.QueryTable(m.TableName()).Filter("username",m.Username).Count()
	if count > 0 {
		return 0,errors.New("用户名不唯一，请重新输入用户名在创建用户!")
	}
	count,_ = o.QueryTable(m.TableName()).Filter("email",m.Email).Count()
	if count > 0 {
		return 0,errors.New("邮箱已经注册过，请输入新的邮箱创建用户!")
	}
	count,_ = o.QueryTable(m.TableName()).Filter("phone",m.Phone).Count()
	if count > 0 {
		return 0, errors.New("电话号码已经注册过,请输入新的电话号码来完成注册!")
	}
	count,_ = o.QueryTable(m.TableName()).Filter("staffnum",m.Staffnum).Count()
	if count > 0 {
		return 0,errors.New("员工号重复，请重新输入新的号码！")
	}
 	id, err = o.Insert(m)
	return
}

// GetTSYSUSERById retrieves TSYSUSER by Id. Returns error if
// Id doesn't exist
func GetUSERById(id int) (v *USER, err error) {
	o := orm.NewOrm()
	v = &USER{Id: id}
	if err = o.Read(v); err == nil {
		return v, nil
	}
	return nil, err
}

func GetUserByUserName(username string) (v *USER, err error) {
	o := orm.NewOrm()
	obj := new(USER)
	// o.Raw("SELECT username,name,email from t_sys_user where username = ?",username).Values(obj)
	err = o.QueryTable("t_sys_user").Filter("username", username).One(obj)
	if err == nil {
		return obj, nil
	}
	return nil, err
}

// GetAllTSYSUSER retrieves all TSYSUSER matches certain condition. Returns empty list if
// no records exist
func GetAllUSER(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{},count int64, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(USER))
	condition := orm.NewCondition()
	enum := 0
	for k, v := range query {
		if strings.Contains(k, "Condition_Join") {
			if strings.Contains(v, "or") {
				enum = 1
			}

		} else {
			k = strings.Replace(k, ".", "__", -1)
			if strings.Contains(k, "isnull") {
				if enum == 0 {
					condition = condition.And(k, (v == "true" || v == "1"))
				}
				if enum == 1 {
					condition = condition.Or(k, (v == "true" || v == "1"))
				}
			} else {
				if enum == 0 {
					condition = condition.And(k, v)
				}
				if enum == 1 {
					condition = condition.Or(k, v)
					enum = 0
				}
			}
		}
	}
	qs = qs.SetCond(condition)
	count, _ = qs.Count()
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil,count, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil,count, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil,count, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil,count, errors.New("Error: unused 'order' fields")
		}
	}

	var l []USER
	qs = qs.OrderBy(sortFields...)
	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				val := reflect.ValueOf(v)
				for _, fname := range fields {
					m[fname] = val.FieldByName(fname).Interface()
				}
				ml = append(ml, m)
			}
		}
		return ml,count, nil
	}
	return nil,count, err
}

// UpdateTSYSUSER updates TSYSUSER by Id and returns error if
// the record to be updated doesn't exist
func UpdateUSERById(m *USER) (err error) {
	o := orm.NewOrm()
	v := USER{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		count, _ := o.QueryTable(m.TableName()).Filter("username",m.Username).Exclude("id",m.Id).Count()
		if count > 0 {
			return errors.New("用户名不唯一，请重新输入用户名在创建用户!")
		}
		count,_ = o.QueryTable(m.TableName()).Filter("email",m.Email).Exclude("id",m.Id).Count()
		if count > 0 {
			return errors.New("邮箱已经注册过，请输入新的邮箱创建用户!")
		}
		count,_ = o.QueryTable(m.TableName()).Filter("phone",m.Phone).Exclude("id",m.Id).Count()
		if count > 0 {
			return errors.New("电话号码已经注册过,请输入新的电话号码来完成注册!")
		}
		count,_ = o.QueryTable(m.TableName()).Filter("staffnum",m.Staffnum).Exclude("staffnum",m.Staffnum).Count()
		if count > 0 {
			return errors.New("员工号重复，请重新输入！")
		}
		m.Password = v.Password
		m.Staffnum = v.Staffnum
		m.Salt = v.Salt
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

func GeneratePassword(id int, password string, salt string)(err error)  {
	o := orm.NewOrm()
	v := USER{Id: id}
	user := USER{}
	if err = o.Read(&v); err == nil {
		var num int64
		user.Password = password
		user.Salt = salt
		user.Id = id
		if num, err = o.Update(&user,"password", "salt"); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteTSYSUSER deletes TSYSUSER by Id and returns error if
// the record to be deleted doesn't exist
func DeleteUSER(id int) (err error) {
	o := orm.NewOrm()
	v := USER{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Delete(&USER{Id: id}); err == nil {
			fmt.Println("Number of records deleted in database:", num)
		}
	}
	return
}
